﻿#region License

// PentaBiz - Sustainable Software Development Framework Copyright (C) 2013 Zoltán Csizmazia
// 
// This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
// 
// This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 

#endregion

using System;
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PentaBiz.Serialization;

namespace PentaBiz.Testing.Serialization
{
    [TestClass]
    public class UnitTestSerializer
    {
        [ClassInitialize]
        public static void TestClassInitialize(TestContext context)
        {
            NetSerializer<MyType>.Initialize();
        }

        [TestMethod]
        [TestCategory("NetSerializer")]
        public void TestSerialize()
        {
            using (var ms = new MemoryStream())
            {
                NetSerializer<MyType>.Serialize(ms, new MyType());
            }
        }

        [TestMethod]
        [TestCategory("NetSerializer")]
        public void TestSerializePerformance1000()
        {
            using (var ms = new MemoryStream())
            {
                for (int i = 0; i < 1000; i++)
                    NetSerializer<MyType>.Serialize(ms, new MyType());

                Console.Write("Stream length: {0} bytes", ms.Length);
            }
        }

        [TestMethod]
        [TestCategory("NetSerializer")]
        public void TestSerializePerformance10000()
        {
            using (var ms = new MemoryStream())
            {
                for (int i = 0; i < 10000; i++)
                    NetSerializer<MyType>.Serialize(ms, new MyType());

                Console.Write("Stream length: {0} bytes", ms.Length);
            }
        }

        [TestMethod]
        [TestCategory("NetSerializer")]
        public void TestDeserialize()
        {
            using (var ms = new MemoryStream())
            {
                NetSerializer<MyType>.Serialize(ms, new MyType());

                ms.Seek(0, SeekOrigin.Begin);

                var d = NetSerializer<MyType>.Deserialize(ms);

                Assert.IsNotNull(d);

                Console.Write("Stream length: {0} bytes", ms.Length);
            }
        }

        [TestMethod]
        [TestCategory("NetSerializer")]
        public void TestDeserializePerformance1000()
        {
            using (var ms = new MemoryStream())
            {
                for (int i = 0; i < 1000; i++)
                    NetSerializer<MyType>.Serialize(ms, new MyType());

                ms.Seek(0, SeekOrigin.Begin);

                for (int i = 0; i < 1000; i++)
                {
                    var d = NetSerializer<MyType>.Deserialize(ms);
                    Assert.IsNotNull(d);
                }

                Console.Write("Stream length: {0} bytes", ms.Length);
            }
        }

        [TestMethod]
        [TestCategory("NetSerializer")]
        public void TestDeserializePerformance10000()
        {
            using (var ms = new MemoryStream())
            {
                for (int i = 0; i < 10000; i++)
                    NetSerializer<MyType>.Serialize(ms, new MyType());

                ms.Seek(0, SeekOrigin.Begin);

                for (int i = 0; i < 10000; i++)
                {
                    var d = NetSerializer<MyType>.Deserialize(ms);
                    Assert.IsNotNull(d);
                }

                Console.Write("Stream length: {0} bytes", ms.Length);
            }
        }

        [TestMethod]
        [TestCategory("NetSerializer")]
        public void TestTwoAndThreeDimensionalArray()
        {
            using (var ms = new MemoryStream())
            {
                var d = new MyType
                    {
                        _2DArray = new double[10,10],
                        _3DArray = new double[10,10,10],
                    };
                InitializeArray(d._2DArray);
                InitializeArray(d._3DArray);


                NetSerializer<MyType>.Serialize(ms, d);

                ms.Seek(0, SeekOrigin.Begin);

                var res = (MyType) NetSerializer<MyType>.Deserialize(ms);

                Assert.IsNotNull(res);
                Assert.IsNotNull(res._2DArray);
                Assert.AreEqual(0, res._2DArray[0, 0]);
                Assert.AreEqual(1, res._2DArray[0, 1]);
                Assert.AreEqual(2, res._2DArray[0, 2]);
                Assert.AreEqual(3, res._2DArray[0, 3]);

                Assert.IsNotNull(res._3DArray);
                Assert.AreEqual(0, res._3DArray[0, 0, 0]);
                Assert.AreEqual(1, res._3DArray[0, 0, 1]);
                Assert.AreEqual(2, res._3DArray[0, 0, 2]);
                Assert.AreEqual(3, res._3DArray[0, 0, 3]);
            }
        }


        [TestMethod]
        [TestCategory("NetSerializer")]
        public void TestTwoAndThreeDimensionalArrayPerformance1000()
        {
            using (var ms = new MemoryStream())
            {
                for (int i = 0; i < 1000; i++)
                {
                    var d = new MyType
                        {
                            _2DArray = new double[10,10],
                            _3DArray = new double[10,10,10],
                        };
                    InitializeArray(d._2DArray);
                    InitializeArray(d._3DArray);


                    NetSerializer<MyType>.Serialize(ms, d);
                }


                ms.Seek(0, SeekOrigin.Begin);

                for (int i = 0; i < 1000; i++)
                {
                    var res = (MyType) NetSerializer<MyType>.Deserialize(ms);

                    Assert.IsNotNull(res);
                    Assert.IsNotNull(res._2DArray);
                    Assert.AreEqual(0, res._2DArray[0, 0]);
                    Assert.AreEqual(1, res._2DArray[0, 1]);
                    Assert.AreEqual(2, res._2DArray[0, 2]);
                    Assert.AreEqual(3, res._2DArray[0, 3]);

                    Assert.IsNotNull(res._3DArray);
                    Assert.AreEqual(0, res._3DArray[0, 0, 0]);
                    Assert.AreEqual(1, res._3DArray[0, 0, 1]);
                    Assert.AreEqual(2, res._3DArray[0, 0, 2]);
                    Assert.AreEqual(3, res._3DArray[0, 0, 3]);
                }

                Console.WriteLine("Serialized size: {0}", ms.Length);
            }
        }

        [TestMethod]
        [TestCategory("NetSerializer")]
        public void TestTwoAndThreeDimensionalArrayPerformance10000()
        {
            using (var ms = new MemoryStream())
            {
                for (int i = 0; i < 10000; i++)
                {
                    var d = new MyType
                        {
                            _2DArray = new double[10,10],
                            _3DArray = new double[10,10,10],
                        };
                    InitializeArray(d._2DArray);
                    InitializeArray(d._3DArray);


                    NetSerializer<MyType>.Serialize(ms, d);
                }

                ms.Seek(0, SeekOrigin.Begin);

                for (int i = 0; i < 10000; i++)
                {
                    var res = (MyType) NetSerializer<MyType>.Deserialize(ms);

                    Assert.IsNotNull(res);
                    Assert.IsNotNull(res._2DArray);
                    Assert.AreEqual(0, res._2DArray[0, 0]);
                    Assert.AreEqual(1, res._2DArray[0, 1]);
                    Assert.AreEqual(2, res._2DArray[0, 2]);
                    Assert.AreEqual(3, res._2DArray[0, 3]);

                    Assert.IsNotNull(res._3DArray);
                    Assert.AreEqual(0, res._3DArray[0, 0, 0]);
                    Assert.AreEqual(1, res._3DArray[0, 0, 1]);
                    Assert.AreEqual(2, res._3DArray[0, 0, 2]);
                    Assert.AreEqual(3, res._3DArray[0, 0, 3]);
                }

                Console.WriteLine("Serialized size: {0}", ms.Length);
            }
        }

        [TestMethod]
        [TestCategory("NetSerializer")]
        public void TestTwoAndThreeDimensionalHugeArrayPerformance1000()
        {
            using (var ms = new MemoryStream())
            {
                for (int i = 0; i < 1000; i++)
                {
                    var d = new MyType
                        {
                            _2DArray = new double[3,1000],
                            //_3DArray = new double[10, 10, 10],
                        };
                    InitializeArray(d._2DArray);
                    //InitializeArray(d._3DArray);


                    NetSerializer<MyType>.Serialize(ms, d);
                }

                ms.Seek(0, SeekOrigin.Begin);

                for (int i = 0; i < 1000; i++)
                {
                    var res = (MyType) NetSerializer<MyType>.Deserialize(ms);

                    Assert.IsNotNull(res);
                    Assert.IsNotNull(res._2DArray);
                    Assert.AreEqual(0, res._2DArray[0, 0]);
                    Assert.AreEqual(1, res._2DArray[0, 1]);
                    Assert.AreEqual(2, res._2DArray[0, 2]);
                    Assert.AreEqual(3, res._2DArray[0, 3]);
                }

                Console.WriteLine("Serialized size: {0}", ms.Length);
            }
        }

        public void InitializeArray(double[,] array)
        {
            double v = 0;
            for (int i = 0; i < array.GetLength(0); i++)
                for (int j = 0; j < array.GetLength(1); j++, v++)
                    array[i, j] = v;
        }

        public void InitializeArray(double[,,] array)
        {
            double v = 0;
            for (int i = 0; i < array.GetLength(0); i++)
                for (int j = 0; j < array.GetLength(1); j++)
                    for (int k = 0; k < array.GetLength(2); k++, v++)
                        array[i, j, k] = v;
        }

        public void InitializeArray(double[] array)
        {
            double v = 0;
            for (int i = 0; i < array.GetLength(0); i++, v++)
                array[i] = v;
        }

        [Serializable]
        private class MyType
        {
            public string Id { get; set; }
            public double[,] _2DArray { get; set; }
            public double[,,] _3DArray { get; set; }
        }
    }
}